const MyKoa = require('./koa.cjs');
const {PassThrough} = require("stream");
const Typer = require("./typer.cjs");

class SSE {
    static eventName = 'chatEventXX'

    static mkEvent = (data) => {
        return `event: ${SSE.eventName}\ndata: ${data}\n\n`
    }

    constructor(ctx, clients) {
        // Set headers and send an initial chat event to just this one client
        ctx.set({
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive',
        });

        ctx.status = 200;

        const event = SSE.mkEvent('Connected')

        // ctx.res.write(event)  // Not work!!!
        // ctx.body = event     // Not work!!!

        const stream = new PassThrough();
        ctx.body = stream;

        stream.write(event)

        clients.push(stream)

        const index = clients.length - 1
        stream.on('close', () => {
            clients.splice(index, 1);
            ctx.res.end();
        })
    }
}

class Server {
    #clients = []

    constructor() {
        new MyKoa(__dirname, __dirname)
            .get([
                ['/', this.index],
                ['/chat', this.acceptNewClient]
            ])
            .post(['/chat', this.broadcastNewMessage])
            .start(3080)
    }

    async index(ctx) {
        await ctx.render(`chatClient`)
    }

    write = (str) => {
        const event = SSE.mkEvent(str)
        this.#clients.forEach(client => client.write(event));
    }

    acceptNewClient = (ctx) => {
        // Remember the response object so we can send future messages to it
        new SSE(ctx, this.#clients)

        // Note that we intentionally do not call response.end() here.
        // Keeping the connection open is what makes Server-Sent Events work.
    }

    broadcastNewMessage = async (ctx) => {
        let request = ctx.req
        let response = ctx.res

        // First, read the body of the request to get the user's message
        request.setEncoding("utf8");

        // const postData = ctx.request.body; // Not work!!!
        let body = "";
        for await (let chunk of request)
            body += chunk;

        // Once we've read the body send an empty response and close the connection
        response.writeHead(200).end();

        new Typer(body, this.write);
    }
}

new Server();
